package com.gitee.feizns.dynamic.convert;

import com.gitee.feizns.dynamic.convert.impl.PrefixMethodConverter;
import com.gitee.feizns.dynamic.convert.impl.SingleParameterStaticMethodConverter;

import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;

/**
 * 使用类型方法转换工具类
 * @see SingleParameterStaticMethodConverter
 * @see PrefixMethodConverter
 * @author feizns
 * @since 2023/04/13
 */
public abstract class MethodConverterUtils {

    /**
     * valueOf 静态方法转换器
     * @see SingleParameterStaticMethodConverter
     */
    public static final Converter<Object, Object> valueOfStaticMethodConverter = new SingleParameterStaticMethodConverter("valueOf");

    /**
     * from 静态方法转换器
     * @see SingleParameterStaticMethodConverter
     */
    public static final Converter<Object, Object> fromStaticMethodConverter = new SingleParameterStaticMethodConverter("from");

    /**
     * toXxx实例方法转换器
     * @see PrefixMethodConverter
     */
    public static final Converter<Object, Object> toPrefixMethodConverter = new PrefixMethodConverter("to");

    /**
     * 常规转换器
     */
    private static final List<Converter<Object, Object>> CONVERTERS = new ArrayList<>(Arrays.asList(valueOfStaticMethodConverter, fromStaticMethodConverter, toPrefixMethodConverter));

    /**
     * 注册转换器
     * @param converter {@link Converter}
     */
    public static void register(Converter<Object, Object> converter) {
        CONVERTERS.add(converter);
    }

    /**
     * 使用使用默认的方法转换器转换类型与类型之间的转换方式
     * @param source 源对象
     * @param targetType 目标类型
     * @return {@link T}
     */
    @SuppressWarnings("unchecked")
    public static <T> T to(Object source, Class<T> targetType) {
        if ( source != null && !targetType.isAssignableFrom(source.getClass()) ) {
            for (Converter<Object, Object> converter : CONVERTERS) {
                Object result = converter.to(source, (Class<Object>) targetType);
                if ( result != null )
                    return (T) result;
            }
            return null;
        }
        return (T) source;
    }

}
